package org.dandsoft.blackbox.evolution.processes;

import org.dandsoft.blackbox.mapreduce.client.operation.Operation;
import org.dandsoft.blackbox.mapreduce.client.operation.OperationException;
import org.dandsoft.blackbox.mapreduce.data.ValueIterator;
import org.dandsoft.blackbox.SignalId;
import org.dandsoft.blackbox.Signal;
import org.dandsoft.blackbox.evolution.BoxNet;
import org.dandsoft.blackbox.evolution.triggers.Trigger;

import java.util.Set;

/**
 * @author Vilyuzhanin Denis (Fin)
 */
public class ActivationOperation extends Operation {

    private BoxNet net;

    public String getOperationName() {
        return ActivationOperation.class.getName();
    }

    /**
     * Сюда приходят пары идентификатор_сигнала=сигнал. Необходимо сформировать пары
     * получатель_сигнала = сигнал, где идентификатор_сигнала и получатель сигнала класс
     * {@link org.dandsoft.blackbox.SignalId}, а сигнал класс {@link org.dandsoft.blackbox.Signal}.
     *
     * @param key   Идентификатор сигнала
     * @param value Сигнал
     * @throws InterruptedException
     * @throws OperationException
     */
    public void map(Object key, Object value) throws InterruptedException, OperationException {
        SignalId signalId = (SignalId) key;

        Set<SignalId> destinations = net.getDestinationSignals(signalId);
        for (SignalId destination : destinations) {
            getContext().emit(destination, value);
        }
    }

    /**
     * Здесь выполняется расчет нового состояния сети.
     *
     * @param key      Идентификатор сигнала чье состояние нужно расчитать. Класс {@link org.dandsoft.blackbox.SignalId}
     * @param iterator Сигналы от которых зависит новое состояние текущего сигнала
     * @throws InterruptedException
     * @throws OperationException
     */
    public void reduce(Object key, ValueIterator iterator) throws InterruptedException, OperationException {
        SignalId signalId = (SignalId) key;
        Trigger trigger = net.getTrigger(signalId);
        while (iterator.hasNext()) {
            Signal signal = (Signal) iterator.next();
            trigger.putSignal(signal);
        }
        Signal result = trigger.getState();
        getContext().emit(result);
    }

    public BoxNet getNet() {
        return net;
    }

    public void setNet(BoxNet net) {
        this.net = net;
    }
}
